package com.niodata.dp.util;

public class PasswordStrengthValidator {

  private int minLength = 8;
  private boolean lowerCaseMustInclude = false;
  private boolean upperCaseMustInclude = false;
  private boolean digitMustInclude = false;
  private boolean specialCharMustInclude = false;

  public PasswordStrengthValidator() {
  }

  public PasswordStrengthValidator(int minLength) {
    this.minLength = minLength;
  }

  public static PasswordStrengthValidator getStrongValidator(int minLength) {
    return new PasswordStrengthValidator(minLength)
          .setLowerCaseMustInclude(true)
          .setUpperCaseMustInclude(true)
          .setDigitMustInclude(true)
          .setSpecialCharMustInclude(true);
  }

  public static PasswordStrengthValidator getDefaultStrongValidator() {
    return new PasswordStrengthValidator(8)
          .setLowerCaseMustInclude(true)
          .setUpperCaseMustInclude(true)
          .setDigitMustInclude(true)
          .setSpecialCharMustInclude(true);
  }

  public int getMinLength() {
    return minLength;
  }

  public PasswordStrengthValidator setMinLength(int minLength) {
    this.minLength = minLength;
    return this;
  }

  public boolean isLowerCaseMustInclude() {
    return lowerCaseMustInclude;
  }

  public PasswordStrengthValidator setLowerCaseMustInclude(boolean lowerCaseMustInclude) {
    this.lowerCaseMustInclude = lowerCaseMustInclude;
    return this;
  }

  public boolean isUpperCaseMustInclude() {
    return upperCaseMustInclude;
  }

  public PasswordStrengthValidator setUpperCaseMustInclude(boolean upperCaseMustInclude) {
    this.upperCaseMustInclude = upperCaseMustInclude;
    return this;
  }

  public boolean isDigitMustInclude() {
    return digitMustInclude;
  }

  public PasswordStrengthValidator setDigitMustInclude(boolean digitMustInclude) {
    this.digitMustInclude = digitMustInclude;
    return this;
  }

  public boolean isSpecialCharMustInclude() {
    return specialCharMustInclude;
  }

  public PasswordStrengthValidator setSpecialCharMustInclude(boolean specialCharMustInclude) {
    this.specialCharMustInclude = specialCharMustInclude;
    return this;
  }

  /**
   * validate password strength.
   *
   * @param password password
   * @throws Exception ex
   */
  public void validate(String password) throws Exception {
    String str = password.replaceAll("\\p{Cntrl}", "")
          .replaceAll(" ", "");
    if (str.length() < password.length()) {
      throw new RuntimeException("密码不能包含空格、控制字符等");
    }
    StringBuffer stringBuffer = new StringBuffer();
    if (password.length() < minLength) {
      stringBuffer.append("密码长度必须至少" + minLength + "个字符,");
    }
    boolean hasLowerChar = false;
    boolean hasUpperChar = false;
    boolean hasDigitChar = false;
    boolean hasSpecialChar = false;
    for (char ch : password.toCharArray()) {
      if (ch >= 'a' && ch <= 'z') {
        hasLowerChar = true;
      } else if (ch >= 'A' && ch <= 'Z') {
        hasUpperChar = true;
      } else if (ch >= '0' && ch <= '9') {
        hasDigitChar = true;
      } else {
        hasSpecialChar = true;
      }
    }
    if (!hasLowerChar && lowerCaseMustInclude) {
      stringBuffer.append("密码必须包含小写字,");
    }

    if (!hasUpperChar && upperCaseMustInclude) {
      stringBuffer.append("密码必须包含大写字,");

    }

    if (!hasDigitChar && digitMustInclude) {
      stringBuffer.append("密码必须包含数字,");
    }

    if (!hasSpecialChar && specialCharMustInclude) {
      stringBuffer.append("密码必须包含特殊字符");
    }
    if (stringBuffer.length() > 0
          && stringBuffer.charAt(stringBuffer.length() - 1) == ',') {
      stringBuffer.deleteCharAt(stringBuffer.length() - 1);
    }
    if (stringBuffer.length() > 0) {
      throw new RuntimeException(stringBuffer.toString());
    }
  }

}
